package com.piece.core.framework.util.validator;

import com.piece.core.framework.util.string.StringUtil;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * hibernate-validator校验工具类
 */
public class ValidatorUtil {

    private static Validator validator;

    static {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    /**
     * 校验对象
     *
     * @param object 待校验对象
     * @param groups 待校验的组
     */
    public static void validate(Object object, Class<?>... groups) throws RuntimeException {
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
        if (!constraintViolations.isEmpty()) {
            ConstraintViolation<Object> constraint = constraintViolations.iterator().next();
            throw new RuntimeException(constraint.getMessage());
        }
    }

    /**
     * 判断是否是正确的IP地址
     */
    public static boolean isIp(String ip) {
        if (StringUtil.isEmpty(ip)) {
            return false;
        }
        return ip.matches(RegexType.IP.value());
    }

    /**
     * 判断是否是正确的邮箱地址
     */
    public static boolean isEmail(String email) {
        if (StringUtil.isEmpty(email)) {
            return false;
        }
        return email.matches(RegexType.EMAIL.value());
    }

    /**
     * 判断是否正整数
     */
    public static boolean isNumber(String number) {
        if (StringUtil.isEmpty(number)) {
            return false;
        }
        return number.matches(RegexType.NUMBER.value());
    }

    /**
     * 判断几位小数
     *
     * @param decimal 数字
     * @param count   小数位数
     */
    public static boolean isDecimal(String decimal, int count) {
        if (StringUtil.isEmpty(decimal)) {
            return false;
        }
        String regex = "^(-)?(([1-9]{1}\\d*)|([0]{1}))(\\.(\\d){" + count + "})?$";
        return decimal.matches(regex);
    }

    /**
     * 判断是否是手机号码
     */
    public static boolean isPhone(String phoneNumber) {
        if (StringUtil.isEmpty(phoneNumber)) {
            return false;
        }
        return phoneNumber.matches(RegexType.PHONE.value());
    }

    /**
     * 验证固话号码
     */
    public static boolean isTelephone(String telephone) {
        if (StringUtil.isEmpty(telephone)) {
            return false;
        }
        return telephone.matches(RegexType.TELEPHONE.value());
    }

    /**
     * 判断是否含有特殊字符
     */
    public static boolean hasSpecialChar(String text) {
        if (StringUtil.isEmpty(text)) {
            return false;
        }
        if (text.replaceAll("[a-z]*[A-Z]*\\d*-*_*\\s*", "").length() == 0) {
            // 如果不包含特殊字符
            return true;
        }
        return false;
    }

    /**
     * 强密码验证
     */
    public static boolean isPassword(String value) {
        if (StringUtil.isEmpty(value)) {
            return false;
        }
        return value.matches(RegexType.PASSWORD.value());
    }

    /**
     * 判断是否含有中文，仅适合中国汉字，不包括标点
     */
    public static boolean isChinese(String text) {
        if (StringUtil.isEmpty(text)) {
            return false;
        }
        Pattern p = Pattern.compile(RegexType.CHINESE.value());
        Matcher m = p.matcher(text);
        return m.find();
    }

    /**
     * 适应CJK（中日韩）字符集，部分中日韩的字是一样的
     */
    public static boolean isChineseCJK(String text) {
        if (StringUtil.isEmpty(text)) {
            return false;
        }

        return text.chars().anyMatch(c -> isChinese((char) c));
    }

    public static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
            return true;
        }
        return false;
    }

    public static boolean isNCName(String text) {
        if (StringUtil.isEmpty(text)) {
            return false;
        }
        return text.matches(RegexType.NCNAME.value());
    }

    public enum RegexType {

        /**
         * 不验证
         */
        NONE(null),

        /**
         * 不含特殊字符
         */
        SPECIALCHAR(""),

        /**
         * 不含中文
         */
        NONECHINESE(""),

        /**
         * 身份证号
         */
        IDCARD(""),

        /**
         * 年([-./_]月([-./_][日]
         */
        DATE("[1-9]{4}([-./_]?)(0?[1-9]|1[0-2])([-./_]?)((0?[1-9])|((1|2)[0-9])|30|31)?"),

        /**
         * 强密码
         */
        PASSWORD("^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{6,18}$"),

        /**
         * 纯中文
         */
        CHINESE("^[\u4E00-\u9FA5]+$"),

        /**
         * 邮箱
         */
        EMAIL("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$"),

        /**
         * IP
         */
        IP("^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
                + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$"),

        /**
         * 网址
         */
        URL("(http://|ftp://|https://|www){0,1}[^\u4e00-\u9fa5\\s]*?\\.(com|net|cn|me|tw|fr)[^\u4e00-\u9fa5\\s]*"),

        /**
         * 数字
         */
        NUMBER("^(-?\\d+)(\\.\\d+)?$"),

        /**
         * 手机号
         */
        PHONE("^((1[3,5,8][0-9])|(14[5,7])|(16[6])|(17[0,6,7,8])|(19[7,8,9]))\\d{8}$"),

        /**
         * 电话号
         */
        TELEPHONE("^(0\\d{2}-\\d{8}(-\\d{1,4})?)|(0\\d{3}-\\d{7,8}(-\\d{1,4})?)$"),

        /**
         * 以字母或下划线开头，后接任意字母、数字、中划线、下划线、句点
         */
        NCNAME("[a-zA-Z_][\\-_.0-9_a-zA-Z$]*");

        RegexType(String value) {
            this.value = value;
        }

        private String value;

        public String value() {
            return value;
        }
    }
}
